//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// This is a sample for BCGControlBar Library Professional Edition
// Copyright (C) 1998-2016 BCGSoft Ltd.
// All rights reserved.
//
// This source code can be used, distributed or modified
// only under terms and conditions 
// of the accompanying license agreement.
//*******************************************************************************
//
// ChartSurfaceView.cpp : implementation file
//

#include "stdafx.h"
#include "bcgpchartexample.h"
#include "ChartSurfaceView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CChartSurfaceView

IMPLEMENT_DYNCREATE(CChartSurfaceView, CBCGPChartExampleView)

CChartSurfaceView::CChartSurfaceView()
	: CBCGPChartExampleView(CChartSurfaceView::IDD)
{
	//{{AFX_DATA_INIT(CChartSurfaceView)
	m_nColorMode = 1;
	m_bUseSoftwareRendering = FALSE;
	m_bEnableAntiAliasing = TRUE;
	m_nTransparency = 0;
	m_bShowCustomPlane = FALSE;
	//}}AFX_DATA_INIT
}

CChartSurfaceView::~CChartSurfaceView()
{
}

void CChartSurfaceView::DoDataExchange(CDataExchange* pDX)
{
	CBCGPChartExampleView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CChartSurfaceView)
	DDX_Control(pDX, IDC_CUSTOM_PLANE, m_wndCustomPlane);
	DDX_Control(pDX, IDC_ROTATE, m_wndRotate);
	DDX_Control(pDX, IDC_CHART, m_wndChart);
	DDX_Control(pDX, IDC_TRANSPARENCY, m_wndTransparency);
	DDX_CBIndex(pDX, IDC_COLOR_MODE, m_nColorMode);
	DDX_Check(pDX, IDC_USE_SOFTWARE_RENDERING, m_bUseSoftwareRendering);
	DDX_Check(pDX, IDC_ENABLE_AA, m_bEnableAntiAliasing);
	DDX_Slider(pDX, IDC_TRANSPARENCY, m_nTransparency);
	DDX_Check(pDX, IDC_CUSTOM_PLANE, m_bShowCustomPlane);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CChartSurfaceView, CBCGPChartExampleView)
	//{{AFX_MSG_MAP(CChartSurfaceView)
	ON_CBN_SELENDOK(IDC_COLOR_MODE, OnUpdateChart)
	ON_BN_CLICKED(IDC_ROTATE, OnRotate)
	ON_WM_HSCROLL()
	ON_REGISTERED_MESSAGE(BCGM_ON_CHART_BEFORE_END_3DDRAW, OnBeforeEnd3DDraw)
	ON_CBN_SELENDOK(IDC_COLOR_COUNT, OnUpdateChart)
	ON_CBN_SELENDOK(IDC_FRAME_STYLE, OnUpdateChart)
	ON_BN_CLICKED(IDC_COLORED_FRAME, OnUpdateChart)
	ON_BN_CLICKED(IDC_ENABLE_AA, OnUpdateChart)
	ON_BN_CLICKED(IDC_WIRE_FRAME, OnUpdateChart)
	ON_BN_CLICKED(IDC_ENABLE_FRAME_TRANSPARENCY, OnUpdateChart)
	ON_BN_CLICKED(IDC_USE_SOFTWARE_RENDERING, OnUpdateChart)
	ON_BN_CLICKED(IDC_ZOOM_SCROLL, OnUpdateChart)
	ON_BN_CLICKED(IDC_CUSTOM_PLANE, OnCustomPlane)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

LRESULT CChartSurfaceView::OnBeforeEnd3DDraw(WPARAM, LPARAM)
{
	CBCGPChartVisualObject* pChart = m_wndChart.GetChart();
	CBCGPChartDiagram3D* pDiagram3D = pChart->GetDiagram3D();

	if (pDiagram3D->GetEngine3D()->IsSoftwareRendering() || !m_bShowCustomPlane)
	{
		return 0;
	}

	//-----------------
	// Draw custom plane:
	//-----------------

	CBCGPChartAxis* pYAxis = pChart->GetChartAxis(BCGP_CHART_Y_PRIMARY_AXIS);
	CBCGPChartAxis* pXAxis = pChart->GetChartAxis(BCGP_CHART_X_PRIMARY_AXIS);
	CBCGPChartAxis* pZAxis = pChart->GetChartAxis(BCGP_CHART_Z_PRIMARY_AXIS);

	// Y plane in chart coordinates
	double dblYPlane = 0.7;

	// convert to normalized axis coordinates - use later to make up plane points
	dblYPlane = pYAxis->PointFromValue(dblYPlane, FALSE);

	// Get normalized coordinates of X and Z minimum/maximum displayed values
	double dblXMinNormal = pXAxis->PointFromValue(pXAxis->GetMinDisplayedValue(), FALSE);
	double dblXMaxNormal = pXAxis->PointFromValue(pXAxis->GetMaxDisplayedValue(), FALSE);
	double dblZMinNormal = pZAxis->PointFromValue(pZAxis->GetMinDisplayedValue(), FALSE);
	double dblZMaxNormal = pZAxis->PointFromValue(pZAxis->GetMaxDisplayedValue(), FALSE);

	// prepare normalized coordinates
	CBCGPPoint ptLeftBottom(dblXMinNormal, dblYPlane, dblZMinNormal);
	CBCGPPoint ptLeftTop(dblXMinNormal, dblYPlane, dblZMaxNormal);
	CBCGPPoint ptRightTop(dblXMaxNormal, dblYPlane, dblZMaxNormal);
	CBCGPPoint ptRightBottom(dblXMaxNormal, dblYPlane, dblZMinNormal);

	// build plane coordinates by converting normalized coordinates to view coordinates
	CBCGPPointsArray arPlane;
	arPlane.Add(pDiagram3D->TransformPoint(ptLeftBottom));
	arPlane.Add(pDiagram3D->TransformPoint(ptLeftTop));
	arPlane.Add(pDiagram3D->TransformPoint(ptRightTop));
	arPlane.Add(pDiagram3D->TransformPoint(ptRightBottom));

	// draw plane polygon using the current theme floor color
	const CBCGPChartTheme& theme = pChart->GetColors();
	CBCGPBrush brPlane; 

	double dblOpacity = bcg_clamp((100 - m_nTransparency) / 100. + 0.2, 0.1, 1.);
	CBCGPColor clrPlane = theme.m_brFloorColor3D.GetColor();
	clrPlane.MakeDarker(0.1);

#ifdef USE_OPENGL
	// Use OpenGL API:

	glEnable(GL_POLYGON_OFFSET_FILL);
	glPolygonOffset(1.0, 1.0);

 	glBegin(GL_POLYGON);
 		glColor4d(clrPlane.r, clrPlane.g, clrPlane.b, dblOpacity);
 		glVertex3d(arPlane[0].x, arPlane[0].y, arPlane[0].z);
 		glVertex3d(arPlane[1].x, arPlane[1].y, arPlane[1].z);
 
 		glVertex3d(arPlane[2].x, arPlane[2].y, arPlane[2].z);
 		glVertex3d(arPlane[3].x, arPlane[3].y, arPlane[3].z);
  	glEnd();

	glDisable(GL_POLYGON_OFFSET_FILL);

	clrPlane.MakeDarker(0.1);

	glLineWidth(2.);
	glBegin(GL_LINE_LOOP);
		glColor4d(clrPlane.r, clrPlane.g, clrPlane.b, dblOpacity);
		glVertex3d(arPlane[0].x, arPlane[0].y, arPlane[0].z);
 		glVertex3d(arPlane[1].x, arPlane[1].y, arPlane[1].z);
 
 		glVertex3d(arPlane[2].x, arPlane[2].y, arPlane[2].z);
 		glVertex3d(arPlane[3].x, arPlane[3].y, arPlane[3].z);
	glEnd();

#else
	brPlane.SetColor(clrPlane, dblOpacity);
	pDiagram3D->GetEngine3D()->FillPolygon(arPlane, brPlane);

	brPlane.MakeDarker(0.1);
	pDiagram3D->GetEngine3D()->DrawPolygon(arPlane, brPlane, 2.);
#endif

	return 0;
}


/////////////////////////////////////////////////////////////////////////////
// CChartSurfaceView diagnostics

#ifdef _DEBUG
void CChartSurfaceView::AssertValid() const
{
	CBCGPChartExampleView::AssertValid();
}

void CChartSurfaceView::Dump(CDumpContext& dc) const
{
	CBCGPChartExampleView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CChartSurfaceView message handlers

void CChartSurfaceView::OnInitialUpdate() 
{
	CBCGPChartExampleView::OnInitialUpdate();
	
	if (m_bIsReady)
	{
		return;
	}

	m_bIsReady = TRUE;

	m_wndTransparency.SetRange(0, 90, TRUE);

	m_wndRotate.GetRotationObject()->SetAutorepeatMode(100);
	m_wndRotate.GetRotationObject()->SetColorTheme(CBCGPRotationObject::BCGP_COLOR_THEME_VISUAL_MANAGER);
	m_wndRotate.GetRotationObject()->EnableFlatIcons();

	CBCGPChartVisualObject* pChart = m_wndChart.GetChart();
	ASSERT_VALID(pChart);

	pChart->SetChartType(BCGPChartSurface3D);

	CBCGPChartAxis* pXAxis = pChart->GetChartAxis(BCGP_CHART_X_PRIMARY_AXIS);
	CBCGPChartAxis* pZAxis = pChart->GetChartAxis(BCGP_CHART_Z_PRIMARY_AXIS);

 	pChart->ShowAxisIntervalInterlacing(BCGP_CHART_Y_PRIMARY_AXIS, TRUE);
 	pChart->ShowAxisIntervalInterlacing(BCGP_CHART_X_PRIMARY_AXIS, FALSE);
 	pChart->ShowAxisIntervalInterlacing(BCGP_CHART_Z_PRIMARY_AXIS, FALSE);

	CBCGPChartSurfaceSeries* pSeries = DYNAMIC_DOWNCAST(CBCGPChartSurfaceSeries, pChart->CreateSeries(_T("Surface")));

	if (m_Feature == CDemoFeature::BCGP_Surface3DBasic)
	{
		double dblStep = 0.03;

		for (double z = 0; z <= 1 + DBL_EPSILON; z += dblStep)
		{
			for (double x = 0; x <= 1 + DBL_EPSILON; x += dblStep)
			{
				double y = sin((x - 0.5) * 2 * M_PI) * sin((z - 0.5) * 2 * M_PI);
				pChart->AddChartDataYXZ(y, x, z);
			}
		}

		pXAxis->SetFixedDisplayRange(0., 1.);
		pZAxis->SetFixedDisplayRange(0., 1.);
	}
	else if (m_Feature == CDemoFeature::BCGP_Surface3DIntersect)
	{
		m_wndCustomPlane.ShowWindow(SW_HIDE);

		CBCGPChartSurfaceSeries* pSeries1 = DYNAMIC_DOWNCAST(CBCGPChartSurfaceSeries, pChart->CreateSeries(_T("Intersecting Surface")));

		double dblStep = 0.2;

		for (double z = -2; z <= 2 + DBL_EPSILON; z += dblStep)
		{
			for (double x = -2; x <= 2 + DBL_EPSILON; x += dblStep)
			{
				double y = x * x + z * z;
				y = cos(y) / (y + 1);

				pChart->AddChartDataYXZ(y, x, z);

	 			double y1 = (x * x + z * z) / 10;
		  		y1 = -((cos(y1) / (y1 + 1) - 0.5)) / 2;
		  
				// add data to intersecting series
				pChart->AddChartDataYXZ(y1 + 0.6, x, z, 1);
			}
		}

		pXAxis->SetFixedDisplayRange(-2., 2.);
		pZAxis->SetFixedDisplayRange(-2., 2.);

		pSeries1->SetSurfaceType(CBCGPChartSurfaceSeries::ST_LEVELS);
		pSeries1->SetLevelRangeMode(CBCGPChartSurfaceSeries::LRM_MINMAX_SERIES);

		pSeries->SetColorMapCount(8);
		pSeries->SetColorMode(CBCGPChartSurfaceSeries::CM_PALETTE);

		pChart->SetShowSurfaceMapInLegend(FALSE);
	}

	pSeries->EnableFrameTransparency();
	pSeries->SetSurfaceType(CBCGPChartSurfaceSeries::ST_LEVELS);
	pSeries->SetLevelRangeMode(CBCGPChartSurfaceSeries::LRM_MINMAX_SERIES);
	pSeries->EnableLevelRangeInLegendLabel(TRUE);

	OnUpdateChart();
}

void CChartSurfaceView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CBCGPChartExampleView::OnHScroll(nSBCode, nPos, pScrollBar);

	if (pScrollBar != NULL)
	{
		OnUpdateChart();
	}
}

void CChartSurfaceView::OnUpdateChart() 
{
	UpdateData();

	CBCGPChartVisualObject* pChart = m_wndChart.GetChart();
	ASSERT_VALID(pChart);

	pChart->GetDiagram3D()->SetRenderingType(
		m_bUseSoftwareRendering ? CBCGPEngine3D::BCGP_RT_SOFTWARE : CBCGPEngine3D::BCGP_RT_OPENGL);
	if (m_bUseSoftwareRendering)
	{
		m_bShowCustomPlane = FALSE;
		UpdateData(FALSE);
	}

	m_wndCustomPlane.EnableWindow(!m_bUseSoftwareRendering);

	for (int i = 0; i < pChart->GetSeriesCount(); i++)
	{
		CBCGPChartSurfaceSeries* pSeries = DYNAMIC_DOWNCAST(CBCGPChartSurfaceSeries, pChart->GetSeries(i));
		ASSERT_VALID(pSeries);

		// for "intersecting surface demo" set options for the second series only
		// otherwise for all
		if (m_Feature != CDemoFeature::BCGP_Surface3DIntersect || i == 1)
		{
			pSeries->SetColorMode((CBCGPChartSurfaceSeries::ColorMode)m_nColorMode);
			pSeries->SetSurfaceOpacity((100 - m_nTransparency) / 100.);	
		}
	}

	pChart->EnableAntialiasing(m_bEnableAntiAliasing);
	pChart->SetDirty(TRUE, TRUE);
}

void CChartSurfaceView::OnRotate() 
{
	CBCGPChartVisualObject* pChart = m_wndChart.GetChart();
	ASSERT_VALID(pChart);

	CBCGPChartDiagram3D* pDiagram3D = pChart->GetDiagram3D();
	ASSERT(pDiagram3D != NULL);

	double xDelta = 5.;
	double yDelta = 5.;
	double persperctiveDelta = 0.1;
	double dblZoomDelta = 0.1;

	double xRotation = pDiagram3D->GetXRotation();
	double yRotation = pDiagram3D->GetYRotation();

	double dblPerspectivePercent = pDiagram3D->GetPerspectivePercent();
	double dblZoomFactor = pDiagram3D->GetZoomFactor();

	switch (m_wndRotate.GetRotationObject()->GetClicked())
	{
	case CBCGPRotationObject::BCGP_ROTATION_UP:
		yRotation += yDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_DOWN:
		yRotation -= yDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_LEFT:
		xRotation -= xDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_RIGHT:
		xRotation += xDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_RESET:
		pDiagram3D->Reset(TRUE);
		pChart->UnZoom();
		dblZoomFactor = 1.;
		return;

	case CBCGPRotationObject::BCGP_ROTATION_NARROW_FIELD_OF_VIEW:
		dblPerspectivePercent -= persperctiveDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_WIDEN_FIELD_OF_VIEW:
		dblPerspectivePercent += persperctiveDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_COUNTER_CLOCKWISE:
		dblZoomFactor += dblZoomDelta;
		break;

	case CBCGPRotationObject::BCGP_ROTATION_CLOCKWISE:
		dblZoomFactor -= dblZoomDelta;
		break;
	}
	
	pDiagram3D->SetPosition(xRotation, yRotation, dblPerspectivePercent);
	pDiagram3D->SetZoomFactor(dblZoomFactor);

	pChart->SetDirty();
	pChart->Redraw();
}

void CChartSurfaceView::OnCustomPlane() 
{
	UpdateData();

	CBCGPChartVisualObject* pChart = m_wndChart.GetChart();
	ASSERT_VALID(pChart);
	
	pChart->Redraw();
}
